package com.rui.generator.util;

import com.rui.common.exception.MyException;
import com.rui.common.util.DateUtil;
import com.rui.generator.entity.Column;
import com.rui.generator.entity.Generator;
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.configuration2.builder.fluent.Configurations;
import org.apache.commons.configuration2.ex.ConfigurationException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.WordUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.zip.ZipOutputStream;

/**
 * 代码生成工具类
 *
 * @author xr
 * @email xr@qq.com
 * @date 2020-01-01 00:00:00
 */
public class GeneratorUtil {

    public static void generator(Generator generator, ZipOutputStream zip) {

//        String moduleName = "helpagent";//微服务模块名称
//        String secModuleName = "business";//二级模块名称
//        String filePath = "D:\\code\\code-gen\\";

        //配置信息
        Configuration config = getConfig();
        String filePath = config.getString("filePath");
        String moduleName = config.getString("moduleName");
        String secModuleName = config.getString("secModuleName");
        boolean hasBigDecimal = false;
        boolean hasDate = false;
        //表名转换成Java类名
        String className = tableToJava(generator.getTable().getTableName(), config.getString("tablePrefix"));
        generator.setClassName(className);
        generator.setClassname(StringUtils.uncapitalize(className));
        //列信息
        List<Column> columns = generator.getColumns();
        for (Column column : columns) {
            int index = columns.indexOf(column);
            //列名转换成Java属性名
            String attrName = columnToJava(column.getColumnName());
            column.setAttrName(attrName);
            column.setAttrname(StringUtils.uncapitalize(attrName));
            //列的数据类型，转换成Java类型
            String attrType = config.getString(column.getDataType(), "unknowType");
            column.setAttrType(attrType);
            if (!hasBigDecimal && "BigDecimal".equals(attrType)) {
                hasBigDecimal = true;
            }
            if (!hasDate && "Date".equals(attrType)) {
                hasDate = true;
            }
            if (index == 0) {
                generator.setPkColumn(column);
            }
        }
        columns.remove(generator.getPkColumn());
        //设置velocity资源加载器
        Properties prop = new Properties();
        prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        Velocity.init(prop);
        String mainPath = config.getString("mainPath");
//        mainPath = StringUtils.isBlank(mainPath) ? "cn.ac.rui" : mainPath;
        //封装模板数据
        Map<String, Object> map = new HashMap<>();
        generator.setPathName(generator.getClassname().toLowerCase());
        generator.setHasBigDecimal(hasBigDecimal);
        generator.setHasDate(hasDate);
        generator.setMainPath(mainPath);
        generator.setPackageName(config.getString("package"));
        generator.setModuleName(config.getString("moduleName"));
        generator.setAuthor(config.getString("author"));
        generator.setEmail(config.getString("email"));
        generator.setDatetime(DateUtil.getCurrentDate());
        map.put("generator", generator);
        VelocityContext context = new VelocityContext(map);
        //获取模板列表
        List<String> templates = getTemplates();
        for (String template : templates) {
            //渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template, String.valueOf(StandardCharsets.UTF_8));
            tpl.merge(context, sw);
            try {

                String fname = getFileName(template, generator.getClassName(), config.getString("package"), moduleName, secModuleName); //config.getString("moduleName"));

//               String fileName = filePath + "src" + File.separator + fname;
                String fileName = filePath + File.separator + fname;
                System.out.println(fileName);

                File f = new File(fileName);
                if(!f.getParentFile().exists()){
                    f.getParentFile().mkdirs();
                }
                f.createNewFile();
                FileOutputStream fos = new FileOutputStream(f);
                String content = sw.toString().replace("${generator.modelName}",generator.getModuleName());
                content = content.replace("${generator.secModuleName}", secModuleName);
                IOUtils.write(content, fos, "UTF-8");

                IOUtils.closeQuietly(sw);
                fos.close();

            } catch (IOException e) {
                throw new MyException("渲染模板失败，表名：" + generator.getTable().getTableName());
            }
        }
    }

    private static Configuration getConfig() {
        Configurations configs = new Configurations();
        try {
            return configs.properties(new File("generator.properties"));
        } catch (ConfigurationException e) {
            throw new MyException("获取配置文件失败");
        }
    }

    private static List<String> getTemplates() {
        List<String> templates = new ArrayList<>();
//        templates.add("templates/AppController.java.vm");
        templates.add("templates/Controller.java.vm");
        templates.add("templates/Model.java.vm");
        templates.add("templates/Res.java.vm");
        templates.add("templates/Req.java.vm");
        templates.add("templates/Mapper.xml.vm");
        templates.add("templates/Mapper.java.vm");
        templates.add("templates/Service.java.vm");
        templates.add("templates/ServiceImpl.java.vm");
        return templates;
    }

    /**
     * 表名转换成Java类名
     */
    private static String tableToJava(String tableName, String tablePrefix) {
        if (StringUtils.isNotBlank(tablePrefix)) {
            tableName = tableName.replaceFirst(tablePrefix, "");
        }
        return columnToJava(tableName);
    }

    /**
     * 列名转换成Java属性名
     */
    private static String columnToJava(String columnName) {
        return WordUtils.capitalizeFully(columnName, new char[]{'_'}).replace("_", "");
    }

    /**
     * 获取文件名
     */
    private static String getFileName(String template, String className, String packageName, String moduleName,String secModuleName) {
//        String packagePath = "main" + File.separator + "java" + File.separator;
//        if (StringUtils.isNotBlank(packageName)) {
            //packagePath += packageName.replace(".", File.separator) + File.separator + moduleName + File.separator;
//            packagePath += packageName.replace(".", File.separator) + File.separator;
//        }

        if (template.contains("Model.java.vm")) {
            String packagePath = ("th-"+moduleName+"-api") + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator;
            return packagePath + File.separator  + "\\cn\\ac\\th\\" + File.separator +   (moduleName+"api")  + File.separator + secModuleName + File.separator  +"model" + File.separator + className + ".java";
        }
        if (template.contains("Res.java.vm")) {
            String packagePath = ("th-"+moduleName+"-api") + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator;
            return packagePath + File.separator  + "\\cn\\ac\\th\\" + File.separator +  (moduleName+"api") + File.separator + secModuleName + File.separator  +"res" + File.separator + className + "Res.java";
        }
        if (template.contains("Req.java.vm")) {
            String packagePath = ("th-"+moduleName+"-api") + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator;
            return packagePath + File.separator  +  "\\cn\\ac\\th\\"+ File.separator  +  (moduleName+"api")  + File.separator + secModuleName + File.separator  +"req" + File.separator + className + "Req.java";
        }

        //----------------------------------

        String packagePath = (moduleName) + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator;
        if (template.contains("Mapper.java.vm")) {
//            return packagePath + "mapper" + File.separator + className + "Mapper.java";
            return packagePath + File.separator   +  "\\cn\\ac\\th\\"+ File.separator  +  moduleName+ File.separator +  secModuleName+ File.separator +"mapper" + File.separator + className + "Mapper.java";
        }
        if (template.contains("Service.java.vm")) {
//            return packagePath + "service" + File.separator + className + "Service.java";
//            String packagePath = ("turingcloud-"+moduleName+"-biz") + "src" + File.separator + "main" + File.separator + "java" + File.separator;
            return packagePath + File.separator   +  "\\cn\\ac\\th\\"+ File.separator  + moduleName + File.separator+
                    secModuleName+ File.separator +"service" + File.separator + className + "Service.java";
        }

        if (template.contains("AppController.java.vm")) {
//            return packagePath + "controller" + File.separator + className + "AppController.java";
//            String packagePath = ("turingcloud-"+moduleName+"-api") + "src" + File.separator + "main" + File.separator + "java" + File.separator;
            return packagePath + File.separator   +  "\\cn\\ac\\th\\"+ File.separator  +   moduleName + File.separator +
                    secModuleName+ File.separator +"app" + File.separator + className + "AppController.java";
        }

        if (template.contains("Controller.java.vm")) {
//            return packagePath + "controller" + File.separator + className + "Controller.java";
//            String packagePath = ("turingcloud-"+moduleName+"-api") + "src" + File.separator + "main" + File.separator + "java" + File.separator;
            return packagePath + File.separator   +  "\\cn\\ac\\th\\"+ File.separator  +   moduleName + File.separator +  secModuleName+ File.separator+"controller" + File.separator + className + "Controller.java";
        }
        if (template.contains("Mapper.xml.vm")) {
//            return "main\\resources\\mapper" + File.separator + className + "Mapper.xml";
//            String packagePath = ("turingcloud-"+moduleName+"-api") + "src" + File.separator + "main" + File.separator + "java" + File.separator;
            return packagePath + File.separator   +  "\\cn\\ac\\th\\"+ File.separator   + moduleName + File.separator +  secModuleName+ File.separator+"mapper" + File.separator + className + "Mapper.xml";
        }

        if (template.contains("ServiceImpl.java.vm")) {
//            return packagePath + "service" + File.separator + className + "ServiceImpl.java";
//            String packagePath = ("turingcloud-"+moduleName+"-api") + "src" + File.separator + "main" + File.separator + "java" + File.separator;
            return packagePath + File.separator  +  "\\cn\\ac\\th\\"+ File.separator   + moduleName + File.separator +  secModuleName+ File.separator +"service"+ File.separator + "impl" + File.separator + className + "ServiceImpl.java";
        }

        return null;
    }
}
